using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
using EventStore.Core.Data;
using EventStore.Core.Messages;
using EventStore.Core.Services.Transport.Tcp;
using EventStore.Transport.Tcp;

namespace EventStore.TestClient.Commands {
	internal class RequestMonitor {
		private ConcurrentQueue<int> _measurements = new ConcurrentQueue<int>();
		private ConcurrentDictionary<Guid, Operation> _operations = new ConcurrentDictionary<Guid, Operation>();
		Stopwatch _watch = new Stopwatch();

		public RequestMonitor() {
			_watch.Start();
		}

		public void StartOperation(Guid id) {
			var record = new Operation();
			record.Start = _watch.ElapsedTicks;
			_operations.AddOrUpdate(id, record, (q, val) => record);
		}

		public void EndOperation(Guid id) {
			Operation record;
			if (_operations.TryRemove(id, out record)) {
				var current = _watch.ElapsedTicks;
				var time = current - record.Start;
				var ms = time / TimeSpan.TicksPerMillisecond;
				_measurements.Enqueue((int)ms);
			} else {
				Console.Write("x");
			}
		}

		public void PrintRawMeasurementDetails() {
			foreach (var i in _measurements) {
				Console.Write(i + ",");
			}
		}

		public void GetMeasurementDetails() {
			var items = _measurements.ToArray();
			Array.Sort(items);
			Console.WriteLine("fastest: " + items[0]);
			Console.WriteLine("quintiles");
			for (int i = 20; i <= 100; i += 20) {
				Console.WriteLine(i + "% : " + items[GetPercentile((decimal)i - 20, items.Length)] + "-" +
				                  items[GetPercentile((decimal)i, items.Length)]);
			}

			Console.WriteLine("90% : " + items[GetPercentile(90m, items.Length)]);
			Console.WriteLine("95% : " + items[GetPercentile(95m, items.Length)]);
			Console.WriteLine("98% : " + items[GetPercentile(98m, items.Length)]);
			Console.WriteLine("99% : " + items[GetPercentile(99m, items.Length)]);
			Console.WriteLine("99.5% : " + items[GetPercentile(99.5m, items.Length)]);
			Console.WriteLine("99.9% : " + items[GetPercentile(99.9m, items.Length)]);
			Console.WriteLine("99.99% : " + items[GetPercentile(99.99m, items.Length)]);
			Console.WriteLine("99.999% : " + items[GetPercentile(99.999m, items.Length)]);
			Console.WriteLine("99.9999% : " + items[GetPercentile(99.9999m, items.Length)]);
			Console.WriteLine("99.99999% : " + items[GetPercentile(99.99999m, items.Length)]);
			Console.WriteLine("Highest : " + items[items.Length - 1]);
		}

		private int GetPercentile(decimal percentile, int size) {
			decimal percent = 0;
			percent = percentile / 100m;
			var ret = (int)(percent * size);
			if (ret == size) ret -= 1;
			return ret;
		}

		struct Operation {
			public long Start;
		}
	}
}
